﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

using SManaApi.Helpers;
using SManaApi.Services;

using SManaModel;
using SManaModel.dtos;
using SManaModel.entities;
using SManaModel.models;
using SManaModel.utils;

using System;

using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using SManaModel.reqs;

namespace SManaApi.Controllers;

/// <summary>
/// 用户模块
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class UserController : MasterController<UserController>
{
    private readonly JwtService _jwtService;
    private readonly StudentService _studentService;
    private readonly TeacherService _teacherService;
    private readonly AccountService _accountService;
    private readonly ApproveService _approveService;

    public UserController(
        ILogger<UserController> logger,
        MyDbContext context,
        TeacherService teacherService,
        AccountService accountService,
        StudentService studentService,
        ApproveService approveService,
        JwtService jwtService) : base(logger, context)
    {
        _studentService = studentService;
        _teacherService = teacherService;
        _accountService = accountService;
        _approveService = approveService;
        _jwtService = jwtService;
    }

    /// <summary>
    /// 分页获取数据
    /// </summary>
    /// <param name="userGetDto"></param>
    /// <returns></returns>
    [HttpGet]
    public ApiResult Get([FromQuery] UserReqDto? userGetDto)
    {
        if (userGetDto == null)
        {
            return ApiResult.FailOfParams();
        }

        #region obsolete
        //var r = userGetDto.type switch
        //{
        //    "student" => GetStudents(userGetDto),
        //    "teacher" => GetTeachers(userGetDto),
        //    "account" => GetAccounts(userGetDto),
        //    _ => ApiResult.Fail("请求错误")
        //};
        #endregion

        var r = userGetDto.type.SelectTypeAction<UserReqDto, ApiResult>(userGetDto,
            dto => GetStudents(userGetDto),
            dto => GetTeachers(userGetDto),
            dto => GetAccounts(userGetDto)
        );
        return r;
    }

    /// <summary>
    /// 获取某个用户的信息
    /// </summary>
    /// <param name="userSelfDto"></param>
    /// <returns></returns>
    [HttpGet("Obj")]
    public ApiResult Get([FromQuery] UserSelfDto userSelfDto)
    {
        if (userSelfDto.id <= 0)
        {
            return ApiResult.FailOfParams();
        }
        var r = userSelfDto.type.SelectTypeAction<UserSelfDto, Object?>(
            userSelfDto,
            dto => _studentService.GetEntity(entity => entity.Id == dto.id)?.FirstOrDefault(),
            dto => _teacherService.GetEntity(entity => entity.Id == dto.id)?.FirstOrDefault(),
            dto => _accountService.GetEntity(entity => entity.Id == dto.id)?.FirstOrDefault()
        );
        if (r != null)
        {
            var out_r = r.ConvertTo<UserShowDto>();
            return ApiResult.Ok(data: out_r);
        }
        else
        {
            return ApiResult.Fail("获取失败");
        }
    }

    /// <summary>
    /// 获取登录账号的信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("Info")]
    public ApiResult Get()
    {
        var stuId = _jwtService.GetId(HttpContext);
        var type = _jwtService.GetType(HttpContext);
        var r = type.SelectTypeAction<int, Object?>(
            stuId,
            dto => _studentService.GetEntity(entity => entity.Id == stuId)?.FirstOrDefault(),
            dto => _teacherService.GetEntity(entity => entity.Id == stuId)?.FirstOrDefault(),
            dto => _accountService.GetEntity(entity => entity.Id == stuId)?.FirstOrDefault()
        );
        if (r != null)
        {
            var out_r = r.ConvertTo<UserShowDto>();
            return ApiResult.Ok(data: out_r);
        }
        else
        {
            return ApiResult.Fail("获取失败");
        }
    }

    /// <summary>
    /// 获取培养人信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("tea_select")]
    public ApiResult GetSelectTeas()
    {
        var out_list = _teacherService.GetEntities()?.OrderBy(t => t.CDate).Select(t => new
        {
            id = t.Id,
            name = t.Name,
        }).ToList();

        return ApiResult.Ok(data: out_list);
    }

    #region GET REQUESTION

    private ApiResult GetStudents(UserReqDto userGetDto)
    {
        #region useless
        //Func<StudentEntity, bool> func = entity =>
        //{
        //    var r = false;
        //    var properties = entity.GetType().GetProperties();
        //    foreach (KeyValuePair<string, string> condition in userGetDto.Conditions)
        //    //foreach (KeyValuePair<string, string> condition in userGetDto.Search.Conditions)
        //    {
        //        var key = condition.Key;
        //        var val = condition.Value;
        //        foreach (var property in properties)
        //        {
        //            var name = property.Name;
        //            if (name.Equals(key, StringComparison.InvariantCultureIgnoreCase))
        //            {
        //                var value = property.GetValue(entity);
        //                r = value.ToString().Contains(val);
        //            }
        //        }
        //    }
        //    return r;
        //};

        //Expression<Func<StudentEntity, bool>> expression =
        //        entity => func(entity);

        //var servicePageComponent = ServicePageComponent<StudentEntity, DateTime>.Create(
        //                    PageComponent.Create(userGetDto),
        //                    entity => entity.CDate,
        //                    expression,
        //                    false);
        //var list = _studentService.GetEntitiesByPage<DateTime>(servicePageComponent);
        #endregion

        var list = _studentService.GetUsersByPage(userGetDto);
        if (list != null && list.Any())
        {
            var outList = list.Select(t => new UserStudentDto
            {
                id = t.Id,
                address = t.Address,
                avatar_url = t.AvatarUrl,
                cdate = t.CDate,
                cls = t.Cls,
                email = t.Email,
                name = t.Name,
                phone = t.Phone,
                politics = t.Politics,
                t2id = t.Teacher2_Id,
                t2name = t.Teacher2.Name,
                tid = t.Teacher_Id,
                tname = t.Teacher.Name,
                username = t.UserName,
            })?.ToList();
            //var outList = list.ConvertTo<UserStudentDto>();
            //var totalNum = _studentService.GetCount();
            var totalNum = _studentService.GetCount();
            return ApiResult.Page(outList!, totalNum!.Value);
        }
        return ApiResult.Fail("没有数据");
    }

    private ApiResult GetTeachers(UserReqDto userGetDto)
    {
        var list = _teacherService.GetUsersByPage(userGetDto)!.ToList();
        if (list is { Count: > 0 })
        {
            var outList = list.ConvertTo<UserShowDto>();
            var totalNum = _teacherService.GetCount();
            return ApiResult.Page(outList!, totalNum!.Value);
        }
        else
        {
            return ApiResult.Fail("没有数据");
        }
    }

    private ApiResult GetAccounts(UserReqDto userGetDto)
    {
        if (userGetDto is null)
        {
            throw new ArgumentNullException(nameof(userGetDto));
        }

        var list = _accountService.GetUsersByPage(userGetDto)!.ToList();
        if (list is { Count: > 0 })
        {
            var outList = list.ConvertTo<UserShowDto>();
            var totalNum = _accountService.GetCount();
            return ApiResult.Page(outList!, totalNum!.Value);
        }
        else
        {
            return ApiResult.Fail("没有数据");
        }
    }
    #endregion

    /// <summary>
    /// 添加用户
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost]
    public ApiResult Add([FromBody] UserAddDto dto)
    {
        var r = dto.type.SelectTypeAction<UserAddDto, ApiResult>(dto,
            dto =>
            {
                var student = dto.ConvertTo<StudentEntity>();
                var n = _studentService.AddEntity(student);
                return ApiResult.Ok(msg: n.ToString());
            },
            dto =>
            {
                var teacher = dto.ConvertTo<TeacherEntity>();
                var n = _teacherService.AddEntity(teacher);
                return ApiResult.Ok(msg: n.ToString());
            },
            dto =>
            {
                var account = dto.ConvertTo<AccountEntity>();
                var n = _accountService.AddEntity(account);
                return ApiResult.Ok(msg: n.ToString());
            });
        return r ?? ApiResult.Fail("请求错误");
    }

    /// <summary>
    /// 删除用户
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpDelete]
    public ApiResult Delete([FromBody] UserDelDto dto)
    {
        #region obsolete
        //if ("student" == dto.type)
        //{
        //    return ApiResult.Ok();
        //}
        //else if ("teacher" == dto.type)
        //{
        //    return ApiResult.Ok();
        //}
        //else if ("account" == dto.type)
        //{
        //    return ApiResult.Ok();
        //}
        //else
        //    return ApiResult.Ok();
        #endregion

        var ids = dto.getIDs();

        var r = dto.type.SelectTypeAction<UserDelDto, ApiResult>(dto,
            dto =>
            {
                foreach (int id in ids)
                {
                    _ = _studentService.DeleteEntity(entity => entity.Id == id);
                }
                return ApiResult.Ok();
            },
            dto =>
            {
                foreach (int id in ids)
                {
                    _ = _teacherService.DeleteEntity(entity => entity.Id == id);
                }
                return ApiResult.Ok();
            },
            dto =>
            {
                foreach (int id in ids)
                {
                    _ = _accountService.DeleteEntity(entity => entity.Id == id);
                }
                return ApiResult.Ok();
            });
        return r ?? ApiResult.Fail("请求错误");
    }

    /// <summary>
    /// 修改用户
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPut]
    public ApiResult Update([FromBody] UserUpdateDto? dto)
    {
        if (dto is null)
        {
            return ApiResult.FailOfParams();
        }

        var r = dto.type.SelectTypeAction<UserUpdateDto, ApiResult>(dto,
            d =>
            {
                var studentEntity = _studentService.GetEntity(t => t.Id == d.id)?.FirstOrDefault();
                if (studentEntity == null)
                {
                    return ApiResult.Fail("该对象不存在");
                }
                studentEntity = d.AssignTo(studentEntity);
                var n = _studentService.UpdateEntity(studentEntity);
                return ApiResult.Ok(msg: n.ToString());
            },
            d =>
            {
                var teacherEntity = _teacherService.GetEntity(t => t.Id == d.id)?.FirstOrDefault();
                if (teacherEntity == null)
                {
                    return ApiResult.Fail("该对象不存在");
                }
                teacherEntity = d.AssignTo(teacherEntity);
                var n = _teacherService.UpdateEntity(teacherEntity);
                return ApiResult.Ok(msg: n.ToString());
            },
            d =>
            {
                var accountEntity = _accountService.GetEntity(t => t.Id == d.id)?.FirstOrDefault();
                if (accountEntity == null)
                {
                    return ApiResult.Fail("该对象不存在");
                }
                accountEntity = d.AssignTo(accountEntity);
                var n = _accountService.UpdateEntity(accountEntity);
                return ApiResult.Ok(n.ToString());
            });
        return r ?? ApiResult.Fail("请求错误");
    }

    /// <summary>
    /// 获取班级
    /// </summary>
    /// <returns></returns>
    [HttpGet("class")]
    public ApiResult GetClass()
    {
        var cls = _teacherService.GetEntities()?.Select(t => t.Cls).ToList();
        return ApiResult.Ok(data: cls);
    }

    /// <summary>
    /// 修改密码
    /// </summary>
    /// <param name="req"></param>
    /// <returns></returns>
    [HttpPut("cpwd")]
    public ApiResult ChangePassword([FromBody] PwdReq req)
    {
        var userId = _jwtService.GetId(HttpContext);
        var r = req.type.SelectTypeAction<PwdReq, ApiResult>(req,
            d =>
            {
                var studentEntity = _studentService.GetEntity(t => t.Id == userId)?.FirstOrDefault();
                if (studentEntity == null)
                {
                    return ApiResult.Fail("该对象不存在");
                }
                if (studentEntity.Password == d.pwd)
                {
                    studentEntity.Password = d.newPwd;
                    var n = _studentService.UpdateEntity(studentEntity);
                    return ApiResult.Ok(msg: n.ToString());
                }
                else
                {
                    return ApiResult.Fail("原密码不一致");
                }
            },
            d =>
            {
                var teacherEntity = _teacherService.GetEntity(t => t.Id == userId)?.FirstOrDefault();
                if (teacherEntity == null)
                {
                    return ApiResult.Fail("该对象不存在");
                }
                if (teacherEntity.Password == d.pwd)
                {
                    teacherEntity.Password = d.newPwd;
                    var n = _teacherService.UpdateEntity(teacherEntity);
                    return ApiResult.Ok(msg: n.ToString());
                }
                else
                {
                    return ApiResult.Fail("原密码不一致");
                }
            },
            d =>
            {
                var accountEntity = _accountService.GetEntity(t => t.Id == userId)?.FirstOrDefault();
                if (accountEntity == null)
                {
                    return ApiResult.Fail("该对象不存在");
                }

                if (accountEntity.Password == d.pwd)
                {
                    accountEntity.Password = d.newPwd;
                    var n = _accountService.UpdateEntity(accountEntity);
                    return ApiResult.Ok(msg: n.ToString());
                }
                else
                {
                    return ApiResult.Fail("原密码不一致");
                }
            });
        return r ?? ApiResult.Fail("请求错误");
    }
}